﻿using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Net;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using DXTools.UI.Core;
using DXTools.Core;
using DXTools.UI.Modules.JavaScriptConverter.Views;
using DXTools.UI.Core.Events;
using System.Collections.Generic;
using DXTools.UI.Modules.JavaScriptConverter.Model;
using DXTools.UI.Modules.JavaScriptConverter.DataProviders;
using DXTools.UI.Core.ViewModel;
using DXTools.Core.CrmSdk;
using System.Collections.ObjectModel;
using System.Text;

namespace DXTools.UI.Modules.JavaScriptConverter.ViewModels
{
    public class JSConverterViewModel : ViewModelBase
    {
        private IDataProvider _dataProvider = null;
        private const string HEADER_INFO = "JavaScript Converter View";

        #region Properties

       

        //public DelegateCommand<object> SearchCommand { get; private set; }

        public DelegateCommand<object> BrowseOriginalJSFileCommand { get; private set; }
        public DelegateCommand<object> SaveCRM2011JSFileCommand { get; private set; }
        public DelegateCommand<object> LoadWebResourceCommand { get; private set; }
        public DelegateCommand<object> SaveWebResourceCommand { get; private set; }
        

        #endregion

        #region Constructors

         public JSConverterViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container)
            :base(regionManager,eventAggregator,container)
        {
            this.HeaderInfo = HEADER_INFO;
            
            this.CloseViewCommand = new DelegateCommand<object>(this.CloseView, this.CanCloseView);
            this.BrowseOriginalJSFileCommand = new DelegateCommand<object>(this.BrowseOriginalJSFiles, this.CanBrowseOriginalJSFile);
            this.SaveCRM2011JSFileCommand = new DelegateCommand<object>(this.SaveCRM2011JSFile, this.CanSaveCRM2011JSFile);
            this.LoadWebResourceCommand = new DelegateCommand<object>(this.LoadWebResource, this.CanLoadWebResource);
            this.SaveWebResourceCommand = new DelegateCommand<object>(this.SaveWebResource, this.CanSaveWebResource);
            
            //this.SearchCommand = new DelegateCommand<object>(this.Search, this.CanSearch);
            
            _dataProvider = new CRMDataProvider();

            LoadJavaScriptWebResourceList();


            eventAggregator.GetEvent<Events.JSConvertEvent>().Subscribe(Convert);
        }

       


         #endregion


         #region Mathods

        private void CloseView(object commandArg)
        {
            base.CloseView();
        }
        private bool CanCloseView(object commandArg)
        {
            return true;
        }

        private bool CanBrowseOriginalJSFile(object commandArg)
        {
            return true;
        }

        private bool CanSaveCRM2011JSFile(object commandArg)
        {
            return !String.IsNullOrEmpty(JavaScriptCodeConverted);
        }

        private bool CanLoadWebResource(object commandArg)
        {
            return (SelectedWebResource != null);
        }

        private bool CanSaveWebResource(object commandArg)
        {
            return (SelectedWebResourceForUpdate != null & !String.IsNullOrEmpty(JavaScriptCodeConverted));
        }

        //private bool CanSearch(object commandArg)
        //{
        //    return true;
        //}

        private String _browseOriginalJSFile;
        public String BrowseOriginalJSFile
        {
            get
            {
                return _browseOriginalJSFile;
            }
            set
            {
                if (value != null)
                {
                    WebResource = null;
                    SelectedWebResource = null;
                }

                _browseOriginalJSFile = value;

                RaisePropertyChanged("BrowseOriginalJSFile");
            }
        }

        private String _javaScriptCode;
        public String JavaScriptCode
        {
            get
            {
                return _javaScriptCode;
            }
            set
            {
                _javaScriptCode = value;
                RaisePropertyChanged("JavaScriptCode");
            }
        }

        private String _javaScriptCodeConverted;
        public String JavaScriptCodeConverted
        {
            get
            {
                return _javaScriptCodeConverted;
            }
            set
            {
                _javaScriptCodeConverted = value;
                RaisePropertyChanged("JavaScriptCodeConverted");
                SaveCRM2011JSFileCommand.RaiseCanExecuteChanged();
                SaveWebResourceCommand.RaiseCanExecuteChanged();
            }
        }

        private XDocument _conversionList;
        public XDocument ConversionList
        {
            get
            {
                return _conversionList;
            }
            set
            {
                _conversionList = value;
                RaisePropertyChanged("ConversionList");
            }
        }


        private Item _selectedWebResource;
        public Item SelectedWebResource
        {
            get
            {
                return _selectedWebResource;
            }
            set
            {
                _selectedWebResource = value;
                SelectedWebResourceForUpdate = value;
                BrowseOriginalJSFile = null;

                RaisePropertyChanged("SelectedWebResource");
                LoadWebResourceCommand.RaiseCanExecuteChanged();

            }
        }

        private Item _selectedWebResourceForUpdate;
        public Item SelectedWebResourceForUpdate
        {
            get
            {
                return _selectedWebResourceForUpdate;
            }
            set
            {
                _selectedWebResourceForUpdate = value;

                RaisePropertyChanged("SelectedWebResourceForUpdate");
                SaveWebResourceCommand.RaiseCanExecuteChanged();

            }
        }

        private ObservableCollection<Item> _webResources;
        public ObservableCollection<Item> WebResources
        {
            get
            {
                return _webResources;
            }
            set
            {
                _webResources = value;
                RaisePropertyChanged("WebResources");
            }

        }

        private WebResource _webResource;
        public WebResource WebResource
        {
            get
            {
                return _webResource;
            }
            set
            {
                _webResource = value;
                RaisePropertyChanged("WebResource");
            }

        }

        public void Convert(string eventArg)
        {

            try
            {
                IsBusy = true;

                if (String.IsNullOrEmpty(JavaScriptCode))
                {
                    MessageBox.Show("You have not provided any Javascript in the Original Script textbox.");
                    return;
                }

                string webResourceName = "dxtools_/JSConverter/ConversionList.xml";

                
                AsyncCallback asyncCallback = (result =>
                {
                    IOrganizationService service = (IOrganizationService)result.AsyncState;
                    EntityCollection response = service.EndRetrieveMultiple(result);

                    Action method = () =>
                    {
                        if(response.Entities.Count > 0)
                        {
                            Entity e = response.Entities[0];
                             

                            byte[] b = System.Convert.FromBase64String(e.Attributes.ContainsKey("content") ? e["content"] as string : string.Empty);
                            string xml = Encoding.UTF8.GetString(b, 0, b.Length);
   
                            ConversionList = XDocument.Load(new StringReader(xml));

                            if (ConversionList != null)
                            {
                                var snippets = from a in ConversionList.Elements()
                                               where a.Name.LocalName == "snippets"
                                               select a;

                                if (snippets.Count() == 0)
                                {
                                    // MessageBox.Show("No conversion items have been found in the Conversion List file. Ensure the Conversion List contains at least one snippet.");
                                    IsBusy = false;
                                    return;
                                }

                                //// Perform the conversion
                                JavaScriptCodeConverted = ConversionHelper.ConvertScript(JavaScriptCode, snippets);
                            }
                            
                        }
                        IsBusy = false;
                    };
                    
                    this.View.Dispatcher.BeginInvoke(method);

                });
                    
                this._dataProvider.RetrieveWebResourceByName(webResourceName, asyncCallback);

                
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occurred during the conversion process. " + ex.Message);
            }
            finally
            {
                IsBusy = false;
            }

        }

        
        private void BrowseOriginalJSFiles(object commandArg)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                dlg.Filter = "JS Files (*.js)|*.js|All Files (*.*)|*.*";
                if (dlg.ShowDialog() == true)
                {
                    IsBusy = true;
                    BrowseOriginalJSFile = dlg.File.Name;
                    JavaScriptCode = Helpers.FileHelper.ReadFile(dlg.File.OpenRead());
                    JavaScriptCodeConverted = null;
                }
            }
            catch (Exception ex)
            {
                // Show error message here
                throw ex;
            }
            finally
            {
                IsBusy = false;
            }
        }

        private void SaveCRM2011JSFile(object commandArg)
        {
            try
            {
                if (string.IsNullOrEmpty(JavaScriptCodeConverted))
                {
                    IsBusy = false;
                    return;
                }

                SaveFileDialog dlg = new SaveFileDialog();
                dlg.Filter = "JS Files (*.js)|*.js|All Files (*.*)|*.*";
                if (dlg.ShowDialog() == true)
                {
                    IsBusy = true;
                    
                    Helpers.FileHelper.SaveFile(JavaScriptCodeConverted, dlg.OpenFile());
                }

            }
            catch (Exception ex)
            {
                // Show error message here
                throw ex;
            }
            finally
            {
                IsBusy = false;
            }
        }

        private void LoadWebResource(object commandArg)
        {
            LoadJavaScriptWebResource();
        }

        private void SaveWebResource(object commandArg)
        {
            SaveJavaScriptWebResource();
        }


        /// <summary>
        /// Load the list of JS WebResources from CRM
        /// </summary>
        private void LoadJavaScriptWebResourceList()
        {

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;

                EntityCollection response = service.EndRetrieveMultiple(result);
                ObservableCollection<Item> webResources = new ObservableCollection<Item>();
                Action method = () =>
                {
                    foreach (Entity e in response.Entities)
                        webResources.Add(
                         new Item()
                         {
                             Value = e.Attributes.ContainsKey("webresourceid") ? ((Guid)e["webresourceid"]).ToString() : String.Empty
                             ,
                             Name = e.Attributes.ContainsKey("name") ? e["name"] as string : string.Empty

                         });
                    this.WebResources = webResources;

                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            this.IsBusy = true;

            this._dataProvider.RetrieveWebResourceList(asyncCallback);
        }

        /// <summary>
        /// Load JS Web Resource and set CRM 4 Script
        /// </summary>
        private void LoadJavaScriptWebResource()
        {

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;

                Entity e = service.EndRetrieve(result);

                Action method = () =>
                {
                    WebResource resource = new WebResource()
                    {
                        WebResourceId = e.Attributes.ContainsKey("webresourceid") ? ((Guid)e["webresourceid"]).ToString() : String.Empty
                           ,
                        Name = e.Attributes.ContainsKey("name") ? e["name"] as string : string.Empty
                            ,
                        DisplayName = e.Attributes.ContainsKey("displayname") ? e["displayname"] as string : string.Empty
                            ,
                        Description = e.Attributes.ContainsKey("description") ? e["description"] as string : string.Empty
                    };

                    byte[] b = System.Convert.FromBase64String(e.Attributes.ContainsKey("content") ? e["content"] as string : string.Empty);

                    string code = Encoding.UTF8.GetString(b, 0, b.Length);

                    resource.Content = code;
                    this.WebResource = resource;
                    this.JavaScriptCode = resource.Content;
                    JavaScriptCodeConverted = null;

                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            this.IsBusy = true;

            this._dataProvider.RetrieveWebResource(SelectedWebResource.Value, asyncCallback);
        }


        /// <summary>
        /// Load JS Web Resource and set CRM 4 Script
        /// </summary>
        private void SaveJavaScriptWebResource()
        {

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;

                service.EndUpdate(result);

                Action method = () =>
                {
                    PublishWebResource();
                    
                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            this.IsBusy = true;

            if (string.IsNullOrEmpty(JavaScriptCodeConverted))
            {
                IsBusy = false;
                return;
            }

            this._dataProvider.UpdateWebResource(SelectedWebResourceForUpdate.Value,JavaScriptCodeConverted, asyncCallback);
        }


        /// <summary>
        /// Load JS Web Resource and set CRM 4 Script
        /// </summary>
        private void PublishWebResource()
        {

            AsyncCallback asyncCallback = (result =>
            {
                IOrganizationService service = (IOrganizationService)result.AsyncState;

                OrganizationResponse response = service.EndExecute(result);

                Action method = () =>
                {

                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            this.IsBusy = true;


            this._dataProvider.PublishWebResource(SelectedWebResourceForUpdate.Value,asyncCallback);
        }


        #endregion


       


    }
}
